#ifndef WIDGET_H
#define WIDGET_H

#include <map>
#include "../Include.h"
#include "../Rectangle.h"
#include "WidgetType.h"
#include "Manager.h"
#include <vector>

namespace PickinOpenSticks {
    namespace Ui {
        /**
         * class Widget: the base ui widget class
         * @author Adrian Tut
         * @date 21/10/2010
         */
        class Widget {
        public:
            friend class Manager;
            typedef std::map<int, Widget*> WidgetList;

            Widget() : index(0), parent(0), focus(0), movable(true), visible(true), mainVisible(true), clicked(false),
            released(false) {
                sprite.SetPosition(0, 0);
                type = WIDGET;
            }

            Widget(const std::string& name) {
                this->name = name;
            }

            virtual ~Widget() {
            }

            virtual void AddWidget(Widget* child);

            inline void SetMovable(bool flag) {
                movable = flag;
            }

            inline void Show() {
                visible = true;
                ShowChildren();
            }

            inline void Hide() {
                visible = false;
                HideChildren();
            }

            inline bool Clicked() {
                return clicked;
            }

            inline bool ClickReleased() {
                bool temp = released;
                released = false;
                return temp;
            }

            inline void SetClicked(bool flag) {
                clicked = flag;
                released = !flag;
            }

            inline void ShowBackground() {
                mainVisible = true;
            }

            inline void HideBackground() {
                mainVisible = false;
            }

            inline WidgetType GetType() const {
                return type;
            }

            inline void SetType(WidgetType type) {
                this->type = type;
            }

            inline const WidgetList& GetWidgetList() {
                return ui;
            }

            inline virtual void SetImage(const sf::Image& image) {
                sprite.SetImage(image);
                pos.SetDimensions(image.GetWidth(), image.GetHeight());
            }

            inline virtual void Resize(int w, int h) {
                pos.w = w;
                pos.h = h;
                sprite.Resize((float) w, (float) h);
            }

            inline virtual void SetPos(int x, int y) {
                pos.x = x;
                pos.y = y;
                sprite.SetPosition((float) x, (float) y);
            }

            inline core::Rectangle& GetPos() {
                return pos;
            }

            inline void SetName(const std::string& newName) {
                name = newName;
            }

            inline const std::string& GetName() const {
                return name;
            }
            Widget* FindChildByName(const std::string& name);

            void RegisterEvent(sf::Event* event);
            virtual void SetDefaultImage();


        private:
            int index; //internally used to keep track of focusing levels
            std::string name; //name of the widget

            inline void Move(int x, int y) {
                if (movable) SetPos(x, y);
            }
            void HideChildren();
            void ShowChildren();
        protected:
            WidgetType type;
            WidgetList ui; //holds the child widgets
            Widget* parent; //the parent widget if any
            Widget* focus; //the child widget in focus if any
            std::vector<sf::Event*> events; //event queue
            sf::Sprite sprite;
            bool movable; //is the widget movable ?
            bool visible; //widget visibily
            bool mainVisible; //background image visibility
            bool clicked; //was the widget clicked ?
            bool released; //was the click released ?
            core::Rectangle pos;

            inline void SetParent(Widget* parent) {
                this->parent = parent;
            }

            inline void AdjustSize() {
                sprite.SetPosition((float) pos.x, (float) pos.y);
                //pos.w = sprite.GetSize().x; pos.h = sprite.GetSize().y;
            }

            inline Widget* GetParent() {
                return parent;
            }

            virtual void Update(int diff);
            virtual void Draw(sf::RenderTarget* target);

            //event handling functions -- overload these in derivate widgets

            virtual void OnClickPressed(sf::Event* event, bool collided = false) {
                SetClicked(true);
                cout << GetName() << ": Click Pressed" << endl;
            }

            virtual void OnClickReleased(sf::Event* event, bool collided = false) {
                SetClicked(false);
                cout << GetName() << ": Click Released" << endl;
            }

            virtual void OnKeyPressed(sf::Event* event) {
                cout << GetName() << ": Key Pressed" << endl;
            }

            virtual void OnKeyReleased(sf::Event* event) {
                cout << GetName() << ": Key Released" << endl;
            }

            virtual void OnOtherEvents(sf::Event* event) {
                cout << GetName() << ": Other Event! " << event->Type << endl;
            }

            virtual void OnTextEntered(sf::Event* event) {
                cout << GetName() << ": TextEntered! : " << (int) event->Text.Unicode << endl;
            }

            //child handling functions -- overload these
            virtual void OnChildEvent(Widget* child, sf::Event* event, bool collided = false);

            virtual void OnChildClickPressed(Widget* child, sf::Event* event, bool collided = false) {
                child->OnClickPressed(event, collided);
            }

            virtual void OnChildClickReleased(Widget* child, sf::Event* event, bool collided = false) {
                child->OnClickReleased(event, collided);
            }

            virtual void OnChildKeyPressed(Widget* child, sf::Event* event) {
                child->OnKeyPressed(event);
            }

            virtual void OnChildKeyReleased(Widget* child, sf::Event* event) {
                child->OnKeyReleased(event);
            }

            virtual void OnChildTextEntered(Widget* child, sf::Event* event) {
                child->OnTextEntered(event);
            }

            virtual void OnChildOtherEvents(Widget* child, sf::Event* event) {
                child->OnOtherEvents(event);
            }
        };
    }
}

#endif
